package com.fs.utils;

import com.alibaba.fastjson.JSON;
import lombok.extern.log4j.Log4j2;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.lang.Nullable;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Log4j2
public class HttpUtils {

    public static class HttpResult {
        private final int statusCode;
        private final String result;

        public HttpResult(int statusCode, String result) {
            this.statusCode = statusCode;
            this.result = result;
        }

        public int getStatusCode() {
            return statusCode;
        }

        public String getResult() {
            return result;
        }
    }

    public static HttpResult get(String url) throws Exception {
        HttpGet httpGet = new HttpGet(url);
        return doRequest(httpGet);
    }

    public static HttpResult postForm(String url, Map<String, String> param) throws Exception {
        HttpPost httpPost = new HttpPost(url);
        List<NameValuePair> pairs = new ArrayList<>();
        param.forEach((k, v) -> pairs.add(new BasicNameValuePair(k, v)));
        UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(pairs, StandardCharsets.UTF_8);
        httpPost.setEntity(formEntity);
        return doRequest(httpPost);
    }

    public static HttpResult postBody(String url, Map<String, Object> param) throws Exception {
        HttpPost httpPost = new HttpPost(url);
        String s = JSON.toJSONString(param);
        StringEntity entity = new StringEntity(s, StandardCharsets.UTF_8.name());
        httpPost.setEntity(entity);
        return doRequest(httpPost);
    }

    public static HttpResult postBody(String url, String param) throws Exception {
        HttpPost httpPost = new HttpPost(url);
        StringEntity entity = new StringEntity(param, StandardCharsets.UTF_8.name());
        httpPost.setEntity(entity);
        return doRequest(httpPost);
    }

    private static HttpResult doRequest(HttpUriRequest req) throws Exception {
        CloseableHttpClient sslClient = createIgnoreSSLHttpClient();
        try (final CloseableHttpResponse response = sslClient.execute(req)) {
            int stateCode = response.getStatusLine().getStatusCode();
            String result = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8.name());
            return new HttpResult(stateCode, result);
        }
    }

    public static CloseableHttpClient createIgnoreSSLHttpClient() throws Exception {
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null,
                (X509Certificate[] chain, String authType) -> true).build();

        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
        return HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory).build();
    }

}